package formater.worker;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;

import jaxb.NodeValue;
import jaxb.Type;

import org.apache.log4j.Logger;

import sun.awt.image.PNGImageDecoder.Chromaticities;

import com.sun.xml.internal.ws.api.server.Container;

import formater.utility.XMLObject;

public class FormaterWorker {
	private static final Logger log = Logger.getLogger(FormaterWorker.class);

	private Type type;

	public FormaterWorker() {
		super();
	}

	public FormaterWorker(URL url) {
		this.type = new XMLObject().getType(url);
	}

	protected void openRawFile(File fIn, File outputPath) {
		try {
			/* Get input */
			String fileName = fIn.getName();
			log.info(fileName); // for test

			/* process */

			// Get open and close token
			List<String> opens = fetchNoteValues(type.getLiveCode().getOpenToken());
			List<String> closes = fetchNoteValues(type.getLiveCode().getCloseToken());
			// Container hold all tokens
			Set<Character> tokens = new HashSet<>();
			int max = 0;
			max = fillTokens(tokens, opens, max);
			max = fillTokens(tokens, closes, max);
			max = fillTokens(tokens, Arrays.asList(type.getTokens().getValue().split(type.getTokens().getToken())), max);

			log.debug(tokens.toString());

			// Open new file reader
			FileReader fr = new FileReader(fIn);
			StringBuilder sb = new StringBuilder();
			StringBuilder tokenStr = new StringBuilder();
			final String indenMerit = type.getIndentation().getMerit();
			int level = 0;
			int count = 0;
			char[] cbuf = new char[1];
			Character c;
			int stepMark = 0;
			while (fr.read(cbuf) != -1) {
				c = cbuf[0];

				if(!c.equals('\n')) {
					if(tokens.contains(c) || tokenStr.length() > 0) {
						tokenStr.append(c);

						if(opens.contains(tokenStr.toString())) {
							// increase level
							stepMark = 1;
						}
						else if(closes.contains(tokenStr.toString())) {
							// decrease level
							stepMark = -1;
						}

						if(tokenStr.length() == max) {
							sb.append(tokenStr); // add to document

							// re-calculate level
							level += stepMark;
							switch (stepMark) {
								case 1:
									break;
								case -1:
									sb.append('\n');
									insertIndents(sb, level, indenMerit);
									break;
								default:
									break;
							}
							log.debug(tokenStr);

							// refresh
							stepMark = 0;
							tokenStr.delete(0, tokenStr.length());
						}
						else {
							continue;
						}
					}
					else {
						sb.append(c); // add to document
					}
				}
			}
			fr.close();

			/* Prepare output */
			File tmp = new File(outputPath, fileName);
			FileWriter fw = new FileWriter(tmp);
			fw.write(sb.toString());
			fw.flush();
			fw.close();
		}catch (IOException e) {
			log.error("", e);
		}
	}

	private void insertIndents(StringBuilder sb, int level, String indenMerit) {
		for(int i = 0; i < level; i++) {
			sb.append(indenMerit);
		}
	}

	private int fillTokens(Set<Character> tokens, List<String> strs, int max) {
		int len = 0;
		for(String str : strs) {
			len = str.length();
			if(len > 0) {
				if(len > max) {
					max = len;
				}
				tokens.add(str.charAt(0));
			}
		}

		return max;
	}

	private List<String> fetchNoteValues(List<NodeValue> nodes) {
		List<String> rs = new ArrayList<>();
		for(NodeValue nv : nodes) {
			rs.add(nv.getValue());
		}

		return rs;
	}

	public void startRun(String[] args) throws Exception {
		URL url = getClass().getResource("/jaxb/artist_html.xml");
		FormaterWorker worker = new FormaterWorker(url);

		url = getClass().getResource("/resources/www.englishclub.com.html");
		worker.openRawFile(new File(url.toURI()), new File("D:/"));
		log.debug(url.getFile());
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			new FormaterWorker().startRun(args);
		}catch (Exception e) {
			log.error("Exception in main", e);
		}
	}

}
